#include "stdafx.h"
#include "GUI.h"

namespace Cvekas {

GUI::GUI(GUIStylePtr gui_style, InputPtr input)
: gui_style(gui_style), input(input), presented(true)
{
}

GUI::~GUI()
{
}

void GUI::doLabel(const Vector2& pos, const std::string& text)
{
	beginWidget();

	gui_style->drawLabel(pos, text);
}

bool GUI::doButton(const Vector2& pos, const std::string& text)
{
	beginWidget();

	//uint id = hashWidget(WIDGET_BUTTON, pos);
	bool mouse_over = gui_style->hitButton(pos, text);
	gui_style->drawButton(pos, text, mouse_over, input->getMouse()->isButtonPressed(Mouse::BTN_LEFT));

	if(mouse_over && input->getMouse()->isButtonUp(Mouse::BTN_LEFT))
		return true;
	return false;
}

bool GUI::doSwitch(const Vector2& pos, const std::string& text)
{
	beginWidget();

	uint id = hashWidget(WIDGET_BUTTON, pos);
	
	if(!cache.exists(id))
	{
		WidgetState temp_state;
		temp_state.switch_state = false;
		cache.set(temp_state, id);
	}
	
	WidgetState& state = cache.at(id);

	bool mouse_over = gui_style->hitSwitch(pos, text);
	gui_style->drawSwitch(pos, text, mouse_over, state.switch_state);

	if(mouse_over && input->getMouse()->isButtonUp(Mouse::BTN_LEFT))
		state.switch_state = !state.switch_state;

	return state.switch_state;
}

float GUI::doSlider(const Vector2& pos)
{
	beginWidget();

	uint id = hashWidget(WIDGET_SLIDER, pos);

	if(!cache.exists(id))
	{
		WidgetState temp_state;
		temp_state.slider_state = 0.5f;
		cache.set(temp_state, id);
	}
	
	WidgetState& state = cache.at(id);

	float mouse_over = gui_style->hitSlider(pos);
	gui_style->drawSlider(pos, mouse_over > 0.0f, state.slider_state);

	if(mouse_over > 0.0f && input->getMouse()->isButtonPressed(Mouse::BTN_LEFT))
		state.slider_state = mouse_over;

	return state.slider_state;
}

uint GUI::doSelector(const Vector2& pos, const std::vector<std::string>& selections)
{
	beginWidget();

	uint id = hashWidget(WIDGET_SELECTOR, pos);

	if(!cache.exists(id))
	{
		WidgetState temp_state;
		temp_state.selector_state = 0;
		cache.set(temp_state, id);
	}

	WidgetState& state = cache.at(id);
	
	assert(state.selector_state < selections.size());

	uint button;
	bool mouse_over = gui_style->hitSelector(pos, selections, button);
	gui_style->drawSelector(pos, selections, state.selector_state, mouse_over, 
		button == 1, button == 2, input->getMouse()->isButtonPressed(Mouse::BTN_LEFT));

	// TODO: implement autorepeat
	if((button == 1) && input->getMouse()->isButtonUp(Mouse::BTN_LEFT))
		state.selector_state = (state.selector_state == 0 ? selections.size() - 1 : state.selector_state - 1);
	if((button == 2) && input->getMouse()->isButtonUp(Mouse::BTN_LEFT))
		state.selector_state = (state.selector_state == (selections.size() - 1) ? 0 : state.selector_state + 1);

	return state.selector_state;
}

bool GUI::getSwitchState(const Vector2& pos)
{
	uint id = hashWidget(WIDGET_BUTTON, pos);
	return cache.at(id).switch_state;
}

float GUI::getSliderState(const Vector2& pos)
{
	uint id = hashWidget(WIDGET_SLIDER, pos);
	return cache.at(id).slider_state;
}

uint GUI::getSelectorState(const Vector2& pos)
{
	uint id = hashWidget(WIDGET_SELECTOR, pos);
	return cache.at(id).selector_state;
}

void GUI::setSwitchState(const Vector2& pos, bool state)
{
	uint id = hashWidget(WIDGET_BUTTON, pos);
	WidgetState dummy;
	dummy.switch_state = state;
	cache.set(dummy, id);
}

void GUI::setSliderState(const Vector2& pos, float state)
{
	uint id = hashWidget(WIDGET_SLIDER, pos);
	WidgetState dummy;
	dummy.slider_state = state;
	cache.set(dummy, id);
}

void GUI::setSelectorState(const Vector2& pos, uint state)
{
	uint id = hashWidget(WIDGET_SELECTOR, pos);
	WidgetState dummy;
	dummy.selector_state = state;
	cache.set(dummy, id);
}

void GUI::present()
{
	if(presented)
		beginWidget();
	else
		presented = true;
	gui_style->endFrame();
}

uint GUI::hashWidget(WidgetType type, const Vector2& pos)
{
	size_t seed = 75621;
	boost::hash_combine(seed, (uint)type);
	boost::hash_combine(seed, pos.x);
	boost::hash_combine(seed, pos.y);

	return (uint)seed;
}

void GUI::beginWidget()
{
	if(presented)
	{
		MousePos mouse_pos = input->getMouse()->getAbsolutePos();
		Vector2 mouse_posf((float)mouse_pos.x, (float)mouse_pos.y);
		gui_style->setMousePos(mouse_posf);
		presented = false;
	}
}

} // namespace